﻿#include "window_app.h"

static const char* ENTER = "\r\n";

HINSTANCE hInstance;
WindowApp* WindowApp::win_app_instance_ = nullptr;

LRESULT CALLBACK MainWndProc(
    HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
  return WindowApp::GetApp()->WndProc(hwnd, msg, wParam, lParam);
}

INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);

WindowApp::WindowApp() { dx_window_ = std::make_unique<ifire::DxWindow>(); }

WindowApp::~WindowApp() {}

void WindowApp::Init(HINSTANCE _instance, LPWSTR lpCmdLine, int nCmdShow) {
  // 将句柄保存到全局
  hInstance = _instance;
  cmd_show_ = nCmdShow;
  win_app_instance_ = this;
  app_exited_ = false;
  // 从项目中读取类名
  LoadString(hInstance, IDC_DX12, szWindowClass, MAX_LOADSTRING);
  // 这行用来适应4K屏幕
  SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
}

bool WindowApp::CreateWinForm(const char* title, UINT width, UINT height) {
  width_ = width;
  height_ = height;

  // 初始化TITLE
  memcpy(szTitle, title, strlen(title));

  MyRegisterClass();

  hwnd_ =
      CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
          CW_USEDEFAULT, width, height, nullptr, nullptr, hInstance, nullptr);

  if (!hwnd_) {
    return false;
  }

  SetupFont();

  ShowWindow(hwnd_, cmd_show_);
  UpdateWindow(hwnd_);

  accel_table_ = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_DX12));

  KLOG("Window created!");

  return true;
}

void WindowApp::RollEvents() {
  if (PeekMessage(&msg_, nullptr, 0, 0, PM_REMOVE)) {
    if (!TranslateAccelerator(msg_.hwnd, accel_table_, &msg_)) {
      TranslateMessage(&msg_);
      DispatchMessage(&msg_);
    }
    // 如果是退出消息，则退出循环
    if (msg_.message == WM_QUIT) {
      app_exited_ = true;
    }
  } else {
    //Sleep(10);
  }
}

//
//  函数: MyRegisterClass()
//
//  目标: 注册窗口类。
//
ATOM WindowApp::MyRegisterClass() {
  WNDCLASSEX wcex;

  wcex.cbSize = sizeof(WNDCLASSEX);

  wcex.style = CS_HREDRAW | CS_VREDRAW;
  wcex.lpfnWndProc = MainWndProc;
  wcex.cbClsExtra = 0;
  wcex.cbWndExtra = 0;
  wcex.hInstance = hInstance;
  wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_DX12));
  wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
  wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  wcex.lpszMenuName = MAKEINTRESOURCE(IDC_DX12);
  wcex.lpszClassName = szWindowClass;
  wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

  return RegisterClassEx(&wcex);
}

RECT WindowApp::GetRect() const {
  RECT rect;
  GetWindowRect(hwnd_, &rect);
  return rect;
}

void WindowApp::RegisterAction(
    const std::string& name, std::function<void()> action) {
  actions_[name] = action;
}

void WindowApp::RegisterCommandHandle(std::function<void(int)> command_handle) {
  command_handle_ = command_handle;
}

void WindowApp::ExecuteAction(const std::string& name) {
  if (actions_.find(name) != actions_.end()) {
    actions_[name]();
  }
}
void WindowApp::ExecuteAction(int index) {
  auto it = actions_.begin();
  std::advance(it, index);
  it->second();
}
//  函数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  目标: 处理主窗口的消息。
//
//  WM_COMMAND  - 处理应用程序菜单
//  WM_PAINT    - 绘制主窗口
//  WM_DESTROY  - 发送退出消息并返回
//
//
LRESULT CALLBACK WindowApp::WndProc(
    HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
  switch (message) {
  case WM_CREATE:
    dx_window_->RegisterWinClass();
    break;
  case WM_COMMAND: {
    int wmId = LOWORD(wParam);
    // 分析菜单选择:
    switch (wmId) {
    case IDM_ABOUT:
      DialogBox(hInstance, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
      break;
    case IDM_EXIT:
      DestroyWindow(hWnd);
      break;
    default:
      if (command_handle_) {
        command_handle_(wmId);
      }

      return DefWindowProc(hWnd, message, wParam, lParam);
    }
  } break;
  case WM_PAINT: {
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hWnd, &ps);

    EndPaint(hWnd, &ps);
  } break;
  case WM_DESTROY:
    if (hWnd == hwnd_) {
      PostQuitMessage(0);
    }

    break;
  case WM_DPICHANGED: {
    RECT* const prcNewWindow = (RECT*)lParam;
    // 调整窗口大小以匹配新的DPI
    SetWindowPos(hWnd, NULL, prcNewWindow->left, prcNewWindow->top,
        prcNewWindow->right - prcNewWindow->left,
        prcNewWindow->bottom - prcNewWindow->top,
        SWP_NOZORDER | SWP_NOACTIVATE);
  } break;
  default:
    return DefWindowProc(hWnd, message, wParam, lParam);
  }
  return 0;
}

// “关于”框的消息处理程序。
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
  UNREFERENCED_PARAMETER(lParam);
  switch (message) {
  case WM_INITDIALOG:
    return (INT_PTR)TRUE;

  case WM_COMMAND:
    if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
      EndDialog(hDlg, LOWORD(wParam));
      return (INT_PTR)TRUE;
    }
    break;
  }
  return (INT_PTR)FALSE;
}

///////////////////////////////////////////////////////////////////////////////
// 窗口控制项目
///////////////////////////////////////////////////////////////////////////////
void WindowApp::SetupFont() {
  font_ = CreateFont(24, // 字体的高度
      0,                 // 字体的宽度
      0,                 // 字体的粗细
      0,                 // 字体是否倾斜
      FW_NORMAL,         // 字体是否带下划线
      FALSE,             // 字体是否带删除线
      FALSE, FALSE,
      DEFAULT_CHARSET,     // 字符集
      OUT_DEFAULT_PRECIS,  // 输出精度
      CLIP_DEFAULT_PRECIS, // 剪切精度
      DEFAULT_QUALITY,     // 输出质量
      FF_DONTCARE,         // 间距和族
      "微软雅黑");
}
HWND WindowApp::AddButton(const char* button_name, int button_id, RECT rect) {
  auto style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON;
  HWND handle =
      CreateWindowEx(0, "button", button_name, style, rect.left, rect.top,
          rect.right, rect.bottom, hwnd_, (HMENU)(UINT_PTR)(button_id), hInstance, NULL);
  SendMessage(handle, WM_SETFONT, (WPARAM)font_, TRUE);
  return handle;
}
HWND WindowApp::CreateLabel(const char* text, RECT rect) {
  auto window_style = WS_CHILD | WS_VISIBLE | SS_LEFT;
  HWND label = CreateWindowEx(0, // 窗口扩展风格
      "STATIC",                  // 预定义的窗口类名
      text,                      // 标签文本
      window_style,              // 窗口风格
      rect.left,                 // X坐标
      rect.top,                  // Y坐标
      rect.right,                // 标签宽度
      rect.bottom,               // 标签高度
      hwnd_,                     // 父窗口
      (HMENU)1,                  // 控制ID
      hInstance,                 // 程序实例句柄
      NULL);                     // 窗口参数
  SendMessage(label, WM_SETFONT, (WPARAM)font_, TRUE);
  return label;
}

void WindowApp::AddTextToEdit(
    HWND handle, const char* str, bool newLine) const {
  /* 以下两条语句为在edit中追加字符串 */
  SendMessage(handle, EM_SETSEL, -2, -1);
  SendMessage(handle, EM_REPLACESEL, true, (LPARAM)str);

  if (newLine) {
    SendMessage(handle, EM_SETSEL, -2, -1);
    SendMessage(handle, EM_REPLACESEL, true, (LPARAM)ENTER);
  }

  /* 设置滚轮到末尾，这样就可以看到最新信息 */
  SendMessage(handle, WM_VSCROLL, SB_BOTTOM, 0);
}

void WindowApp::SetFont(HWND target) {
  SendMessage(target, WM_SETFONT, (WPARAM)font_, TRUE);
}

HWND WindowApp::CreateTextArea(RECT rect) {
  auto style =
      WS_CHILD | WS_VISIBLE | ES_AUTOVSCROLL | WS_VSCROLL | ES_MULTILINE;
  HWND handle = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", NULL, style, rect.left,
      rect.top, rect.right, rect.bottom, hwnd_, NULL, NULL, NULL);
  SendMessage(handle, EM_SETLIMITTEXT, (WPARAM)100000, 0);
  SetFont(handle);
  return handle;
}
